package br.academia.controller;

import java.util.ArrayList;
import java.util.Collection;

import javax.faces.model.SelectItem;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import br.academia.arq.dao.UsuarioDAO;
import br.academia.arq.erros.DAOException;
import br.academia.arq.erros.NegocioException;
import br.academia.dominio.Usuario;
import br.academia.negocio.AbstractProcessador;
import br.academia.negocio.UsuarioProcessador;
import br.academia.util.Validador;

@SuppressWarnings("serial")
@Component("usuario")
@Scope("session")
public class UsuarioController extends AbstractController{
	/** JSPs chamadas pelo Controller */
	public static final String LOGIN_JSP = "/admin/usuario/login_usuario.jsf";
	public static final String CADASTRAR_JSP = "/admin/usuario/cadastrar_usuario.jsf";
	public static final String ALTERAR_JSP = "/admin/usuario/alterar_usuario.jsf";
	public static final String LISTAR_JSP = "/admin/usuario/listar_usuario.jsf";
	public static final String MENU_JSP = "/admin/usuario/menu_usuario.jsf";
	
	/** Objeto usado nos fluxos do Controller */
	private Usuario usuario;
	
	/** Atributos usados nas listagens do Controller */
	private String login;
	private String senha;
	
	/** Lista populada pelos fluxos */
	private Collection<Usuario> listaUsuarios;

	/** Combo de Usuarios */
	private Collection<SelectItem> comboUsuarios;
	
	public Collection<SelectItem> getComboUsuarios(){
		if(Validador.isEmpty(comboUsuarios)){
			UsuarioDAO dao = null;
			try {
				dao = getDAO(UsuarioDAO.class);
				
				comboUsuarios = toSelectItems(dao.findAll(Usuario.class), "id", "nome");
			} catch (DAOException e) {
				addMensagem("Ocorreu um erro na geração da lista de Usuarios. Por favor, contate a administração do sistema.");
				postarMensagens();
				e.printStackTrace();
			}finally{
				close(dao);
			}
		}
		
		return comboUsuarios;
	}
	
	/**
	 * Construtor público
	 */
	public UsuarioController(){
		reset();
	}
	
	/**
	 * Método usado para reiniciar os atributos do Controller
	 */
	public void reset(){
		usuario = new Usuario();
		listaUsuarios = new ArrayList<Usuario>();
		login = "";
		senha = "";
	}
	
	/**
	 * Método utilizado para entrar no menu de Estado
	 * @return
	 */
	public String entrarMenu(){
		reset();
		
		return forward(MENU_JSP);
	}
	
	/**
	 * Método utilizado para entrar na listagem de Estado
	 * @return
	 */
	public String entrarListagem(){
		reset();
		
		return listar();
	}
	
	/**
	 * Método que popula a lista de Estados e redireciona para a listagem
	 * @return
	 */
	public String listar(){
		UsuarioDAO dao = null;
		
		try {
			dao = getDAO(UsuarioDAO.class);
			
			if(Validador.isEmpty(login) && Validador.isEmpty(senha)){
				listaUsuarios = dao.findAll(Usuario.class);
			}else{
				setValores();
				
				listaUsuarios = dao.findUsuarioLike(usuario);
			}
		} catch (DAOException e) {
			addMensagem("Ocorreu um erro na listagem de Usuarios. Por favor, contate a administração do sistema.");
			e.printStackTrace();
			return reload();
		}finally{
			if(dao != null){
				dao.close();
			}
		}
		
		if(hasMensagens()){
			return reload();
		}
		
		if(listaUsuarios.isEmpty()){
			addMensagem("Não foi encontrado nenhum Usuario para a busca realizada.");
		}
		
		return forward(LISTAR_JSP);
	}
	
	/**
	 * Método utilizado para entrar na página de alteração de Estados
	 * @return
	 */
	public String entrarAlteracao(){
		reset();
		UsuarioDAO dao = null;
		
		Integer id = Integer.valueOf(getParameter("id"));
		
		if(id == null || id <= 0){
			addMensagem("Ocorreu um erro na alteração do Usuarios selecionado. Por favor, contate a administração do sistema.");
			return reload();
		}
		
		try {
			dao = getDAO(UsuarioDAO.class);
			
			usuario = dao.findByPrimaryKey(id, Usuario.class);
			
			login = usuario.getLogin();
			senha = usuario.getSenha();
		} catch (DAOException e) {
			e.printStackTrace();
		}finally{
			close(dao);
		}
		return forward(ALTERAR_JSP);
	}
	
	/**
	 * Método que realiza a chamada à classe de negócio que realiza
	 * a atualização do Estado na base de dados.
	 * @return
	 */
	public String alterar(){
		addMensagem(Validador.validaPreenchimento("Login", login));
		addMensagem(Validador.validaPreenchimento("Senha", senha));
		
		if(hasMensagens()){
			return reload();
		}
		
		setValores();
		
		UsuarioProcessador processador = new UsuarioProcessador();
		
		try {
			processador.execute(AbstractProcessador.ALTERAR, usuario);
		} catch (NegocioException e) {
			addMensagem(e.getMessage());
			return reload();
		}
		
		return entrarListagem();
	}
	
	/**
	 * Método utilizado para entrar na página de cadastro de Usuarios
	 * @return
	 */
	public String entrarCadastro(){
		reset();
		
		return forward(CADASTRAR_JSP);
	}
	
	/**
	 * Método que realiza a chamada à classe de negócio que realiza
	 * a inserção do Estado na base de dados.
	 * @return
	 */
	public String cadastrar(){
		addMensagem(Validador.validaPreenchimento("Login", login));
		addMensagem(Validador.validaPreenchimento("Senha", senha));
		
		if(hasMensagens()){
			return reload();
		}
		
		setValores();
		
		UsuarioProcessador processador = new UsuarioProcessador();
		
		try {
			processador.execute(AbstractProcessador.CADASTRAR, usuario);
		} catch (NegocioException e) {
			addMensagem(e.getMessage());
		}

		addMensagem("Usuário cadastrado com sucesso.");
		
		if(Validador.isEmpty(getUsuarioLogado())){
			return entrarLogin();
		}
		
		return entrarListagem();
	}
	
	/**
	 * Método utilizado na página de listagem de Estados, para remover
	 * um Estado selecionado.
	 * @return
	 */
	public String remover(){
		Integer id = Integer.valueOf(getParameter("id"));
		
		if(id == null || id <= 0){
			addMensagem("Ocorreu um erro na remoção do item selecionado. Por favor, contate a administração do sistema.");
			return reload();
		}
		
		usuario.setId(id);
		
		UsuarioProcessador processador = new UsuarioProcessador();
		
		try {
			processador.execute(AbstractProcessador.REMOVER, usuario);
		} catch (NegocioException e) {
			addMensagem(e.getMessage());
		}
		
		return entrarListagem();
	}
	
	/**
	 * Método utilizado para entrar na página de cadastro de Usuarios
	 * @return
	 */
	public String entrarLogin(){
		reset();
		
		return forward(LOGIN_JSP);
	}
	
	/**
	 * Método que realiza a chamada à classe de negócio que realiza
	 * a inserção do Estado na base de dados.
	 * @return
	 */
	public String login(){
		addMensagem(Validador.validaPreenchimento("Login", login));
		addMensagem(Validador.validaPreenchimento("Senha", senha));
		
		if(hasMensagens()){
			return reload();
		}
		
		UsuarioDAO dao = null;
		
		try {
			dao = getDAO(UsuarioDAO.class);
			setValores();
			
			Usuario usuarioLogado = dao.findUsuarioByLoginSenha(usuario.getLogin(), usuario.getSenha());
			setUsuarioLogado(usuarioLogado);
		} catch (DAOException e) {
			addMensagem("Ocorreu um erro no login do Usuario. Por favor, contate a administração do sistema.");
			e.printStackTrace();
			return reload();
		}finally{
			if(dao != null){
				dao.close();
			}
		}
		
		reset();
		
		return entrarHome();
	}
	
	/**
	 * Método utilizado para realizar logout do sistema
	 * @return
	 */
	public String logout(){
		reset();
		
		setUsuarioLogado(null);
		
		return entrarHome();
	}
	
	/**
	 * Método utilizado para exigir login no sistema
	 * @return
	 */
	public String loginRequired(){
		reset();
		
		addMensagem("Sua sessão expirou. Por favor, realize login para continuar utilizando o sistema.");
		
		setUsuarioLogado(null);
		
		return entrarHome();
	}
	
	/**
	 * Método utilizado para cancelar a operação em curso
	 * @return
	 */
	public String cancelar(){
		return entrarMenu();
	}
	
	public Usuario getUsuario() {
		return usuario;
	}

	public void setUsuario(Usuario usuario) {
		this.usuario = usuario;
	}

	private void setValores(){
		usuario.setLogin(login.trim());
		usuario.setSenha(senha);
	}

	public String getLogin() {
		return login;
	}

	public void setLogin(String login) {
		this.login = login;
	}

	public String getSenha() {
		return senha;
	}

	public void setSenha(String senha) {
		this.senha = senha;
	}

	public Collection<Usuario> getListaUsuarios() {
		return listaUsuarios;
	}

	public void setListaUsuarios(Collection<Usuario> listaUsuarios) {
		this.listaUsuarios = listaUsuarios;
	}
}
